<html>
 <head>
  <meta charset="UTF-8">
 </head>
 <body>
  <h1 data-lake-id="D025e" id="D025e"><span data-lake-id="u6074e3fa" id="u6074e3fa">典型回答</span></h1>
  <p data-lake-id="u2f4ea463" id="u2f4ea463"><br></p>
  <p data-lake-id="u82094d18" id="u82094d18"><span data-lake-id="u486a598b" id="u486a598b">其实，使用二级缓存也能解决循环依赖的问题，但是如果完全依靠二级缓存解决循环依赖，意味着当我们依赖了一个代理类的时候，就需要在Bean实例化之后完成AOP代理。而在Spring的设计中，为了解耦Bean的初始化和代理，是通过AnnotationAwareAspectJAutoProxyCreator这个后置处理器来在Bean生命周期的最后一步来完成AOP代理的。</span></p>
  <p data-lake-id="u0dc58468" id="u0dc58468"><span data-lake-id="ud27e74df" id="ud27e74df">​</span><br></p>
  <p data-lake-id="u6caa9b72" id="u6caa9b72"><span data-lake-id="uce3ad9a4" id="uce3ad9a4">但是，在Spring的初始化过程中，他是不知道哪些Bean可能有循环依赖的，那么，这时候Spring面临两个选择：</span></p>
  <p data-lake-id="ud05f24ae" id="ud05f24ae"><br></p>
  <ol list="u61721921">
   <li fid="u8a5c69a8" data-lake-id="uee53af5b" id="uee53af5b"><span data-lake-id="u9e85f591" id="u9e85f591">不管有没有循环依赖，都提前把代理对象创建出来，并将代理对象缓存起来，出现循环依赖时，其他对象直接就可以取到代理对象并注入。</span></li>
   <li fid="u8a5c69a8" data-lake-id="ua659f83b" id="ua659f83b"><span data-lake-id="u6f582021" id="u6f582021">不提前创建代理对象，在出现循环依赖时，再生成代理对象。这样在没有循环依赖的情况下，Bean就可以按着Spring设计原则的步骤来创建。</span></li>
  </ol>
  <p data-lake-id="u1648ddd3" id="u1648ddd3"><br></p>
  <p data-lake-id="ubc254296" id="ubc254296"><span data-lake-id="u19ffe2fe" id="u19ffe2fe">第一个方案看上去比较简单，只需要二级缓存就可以了。但是他也意味着，Spring需要在所有的bean的创建过程中就要先成代理对象再初始化；那么这就和spring的aop的设计原则（前文提到的：在Spring的设计中，为了解耦Bean的初始化和代理，是通过AnnotationAwareAspectJAutoProxyCreator这个后置处理器来在Bean生命周期的最后一步来完成AOP代理的）是相悖的。</span></p>
  <p data-lake-id="ub80f5d47" id="ub80f5d47"><span data-lake-id="ube6a125c" id="ube6a125c">​</span><br></p>
  <p data-lake-id="u887ccce0" id="u887ccce0"><span data-lake-id="u4f4574c6" id="u4f4574c6">而Spring为了不破坏AOP的代理设计原则，则引入第三级缓存，在三级缓存中保存对象工厂，因为通过对象工厂我们可以在想要创建对象的时候直接获取对象。有了它，在后续发生循环依赖时，如果依赖的Bean被AOP代理，那么通过这个工厂获取到的就是代理后的对象，如果没有被AOP代理，那么这个工厂获取到的就是实例化的真实对象。</span></p>
  <p data-lake-id="ua3ac8157" id="ua3ac8157"><br></p>
  <h1 data-lake-id="dlD6t" id="dlD6t"><span data-lake-id="u23c16335" id="u23c16335">扩展知识</span></h1>
  <p data-lake-id="u86e0067f" id="u86e0067f"><br></p>
  <p data-lake-id="u5b92dfe4" id="u5b92dfe4"><span data-lake-id="u73959b00" id="u73959b00">其实，只用二级缓存，也是可以解决循环依赖的问题的，如下图，没有三级缓存，只有二级缓存的话，也是可以解决循环依赖的。</span></p>
  <p data-lake-id="u464390fe" id="u464390fe"><span data-lake-id="ued800c90" id="ued800c90">​</span><br></p>
  <p data-lake-id="u870730be" id="u870730be"><img src="https://cdn.nlark.com/yuque/0/2023/png/5378072/1696145435255-b2220a12-83a7-4035-acd3-96727d02b028.png?x-oss-process=image%2Fwatermark%2Ctype_d3F5LW1pY3JvaGVp%2Csize_59%2Ctext_SmF2YSA4IEd1IFA%3D%2Ccolor_FFFFFF%2Cshadow_50%2Ct_80%2Cg_se%2Cx_10%2Cy_10"></p>
  <p data-lake-id="u1355f3d0" id="u1355f3d0"><br></p>
  <p data-lake-id="ue1896217" id="ue1896217"><span data-lake-id="uf44fec06" id="uf44fec06">那么，为什么还需要引入三级缓存呢？我们看下两个过程的区别主要是什么呢？</span></p>
  <p data-lake-id="u63d70cb3" id="u63d70cb3"><span data-lake-id="u0f7817e7" id="u0f7817e7">​</span><br></p>
  <p data-lake-id="u517edc2f" id="u517edc2f"><img src="https://cdn.nlark.com/yuque/0/2023/png/5378072/1696145469111-1d94782a-cfd9-45e2-a9ba-fadb4679c2ae.png?x-oss-process=image%2Fwatermark%2Ctype_d3F5LW1pY3JvaGVp%2Csize_66%2Ctext_SmF2YSA4IEd1IFA%3D%2Ccolor_FFFFFF%2Cshadow_50%2Ct_80%2Cg_se%2Cx_10%2Cy_10"></p>
  <p data-lake-id="ub0259ca6" id="ub0259ca6"><span data-lake-id="u2d08708c" id="u2d08708c">我给大家标出来了，如果使用三级缓存，在实例化之后，初始化之前，向三级缓存中保存的是ObjectFactory。而如果使用二级缓存，那么在这个步骤中保存的就是具体的Object。</span></p>
  <p data-lake-id="ue5d56f0c" id="ue5d56f0c"><span data-lake-id="u01812812" id="u01812812">​</span><br></p>
  <p data-lake-id="u7836f31e" id="u7836f31e"><span data-lake-id="u89aa024f" id="u89aa024f">这里如果我们只用二级缓存，对于普通对象的循环依赖问题是都可以正常解决的，但是如果是代理对象的话就麻烦多了，并且AOP又是Spring中很重要的一个特性，代理又不能忽略。</span></p>
  <p data-lake-id="u10c11625" id="u10c11625"><span data-lake-id="uc5de87cb" id="uc5de87cb">​</span><br></p>
  <p data-lake-id="u29a1440d" id="u29a1440d"><span data-lake-id="u5ff5dd11" id="u5ff5dd11">我们都知道，我们是可以在一个ServiceA中注入另外一个ServiceB的代理对象的，那么在解决循环依赖过程中，如果需要注入ServiceB的代理对象，就需要把ServiceB的代理对象创建出来，但是这时候还只是ServiceB的实例化阶段，代理对象的创建要等到初始化之后，在后置处理的postProcessAfterInitialization方法中对初始化后的Bean完成AOP代理的。</span></p>
  <p data-lake-id="uc635915b" id="uc635915b"><span data-lake-id="uc39e3a7b" id="uc39e3a7b">​</span><br></p>
  <p data-lake-id="uc726d360" id="uc726d360"><span data-lake-id="ud3425e58" id="ud3425e58">那怎么办好呢？Spring想到了一个好的办法，那就是使用三级缓存，并且在这个三级缓存中，并没有存入一个实例化的对象，而是存入了一个匿名类</span><span data-lake-id="uba963059" id="uba963059" class="lake-fontsize-12" style="color: rgb(51, 51, 51)">ObjectFactory（其实本质是一个</span><span data-lake-id="u4079df4b" id="u4079df4b">函数式接口</span><code data-lake-id="u2d26be1d" id="u2d26be1d"><span data-lake-id="ua705a1b3" id="ua705a1b3">() -&gt; getEarlyBeanReference(beanName, mbd, bean)</span></code><span data-lake-id="u1613d20e" id="u1613d20e">），具体代码如下：</span></p>
  <p data-lake-id="ucbe9ba9b" id="ucbe9ba9b"><span data-lake-id="u4904c77c" id="u4904c77c">​</span><br></p>
  <pre lang="java"><code>
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory
		implements AutowireCapableBeanFactory {
  protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
    throws BeanCreationException {
    ....
    
    // 如果允许循环引用，且beanName对应的单例bean正在创建中，则早期暴露该单例bean，以便解决潜在的循环引用问题
    	boolean earlySingletonExposure = (mbd.isSingleton() &amp;&amp; this.allowCircularReferences &amp;&amp;
    			isSingletonCurrentlyInCreation(beanName));
    	if (earlySingletonExposure) {
    		if (logger.isTraceEnabled()) {
    			logger.trace("Eagerly caching bean '" + beanName +
    					"' to allow for resolving potential circular references");
    		}
    		// 向singletonFactories添加该beanName及其对应的提前引用对象，以便解决潜在的循环引用问题
    		addSingletonFactory(beanName, () -&gt; getEarlyBeanReference(beanName, mbd, bean));
    	}
    
    ...
    }
}

</code></pre>
  <p data-lake-id="uc8858f20" id="uc8858f20"><br></p>
  <p data-lake-id="u85065758" id="u85065758"><br></p>
  <p data-lake-id="uc8279f61" id="uc8279f61"><br></p>
 </body>
</html>